# -*- coding: utf-8 -*-
from openerp.osv import fields
from openerp.osv import osv
from datetime import datetime
import re, hashlib


class sale_order_express_delivery(osv.osv):
    _name = "sale.order.express.delivery"
    _columns = {
        'so_id': fields.many2one('sale.order', u'销售订单'),
        'consignee': fields.char(u'收货人'),
        'mobile_number': fields.char(u'手机号码'),
        'phone_number': fields.char(u'电话'),
        'province': fields.char(u'省'),
        'city': fields.char(u'市'),
        'county': fields.char(u'县'),
        'street': fields.char(u'详细地址'),
        'delivery_products': fields.text(u'发货内容'),
        'note': fields.text(u'备注'),
        'express_type_id': fields.many2one('express.type', u'快递方式'),
        'express_code': fields.char(u'快递单号'),
        'express_fee': fields.float(u'快递费用'),
        'is_exported': fields.boolean(u'已导出'),
        'export_uid':fields.many2one('res.users',u'导出人'),
        'export_date':fields.datetime(u'导出时间'),
        'qty_note': fields.char(u'数量(A2B1C3个数)'),
        'order_line_json': fields.text(u'{"销售订单行ID": [数量, 数量] )]'),
        'picking_id': fields.many2one('stock.picking', string="出库单"),
        'address_hash': fields.char(u'地址信息hash')
    }

    def hashlib_express_val(self, val):
        """hash 一下  用户的快递地址信息，以便于对比，避免重复导入"""
        md5 = hashlib.md5()
        md5.update(val)
        return md5.hexdigest()

    def unlink(self, cr, uid, ids, context=None):
        """ 快递发货地址被仓库导出后，如果再进行删除要报错。 """
        for express_delivery in self.browse(cr, uid, ids, context=context):
            if express_delivery.is_exported:
                raise osv.except_osv(u'错误', u'快递发货地址已被仓库导出，不能删除！')
        return super(sale_order_express_delivery, self).unlink(cr, uid, ids, context=context)

    def create_picking_out_sale(self, cr, uid, ids, context=None):
        line_obj = self.pool.get("sale.order.line")
        sale_obj = self.pool.get("sale.order")
        wizard_obj = self.pool.get("confirm.out.going.wizard")
        for sale_delivery in self.browse(cr, uid, ids, context=context):
            if sale_delivery.is_exported:
                raise osv.except_osv(u'错误', u'已导出无法生成出库单！')
            sale_note = sale_delivery.delivery_products
            if '\n' in sale_note or ' × ' in sale_note:
                for line_note in sale_note.split('\n'):
                    if ' × ' in line_note:
                        line_not_list = line_note.split(' × ')
                        line_row = line_obj.search(cr, uid, [('product_id', '=', line_not_list[0]),
                                                             ('order_id', '=', sale_delivery.so_id.id)], context=context)
                        if len(line_row) != 1:
                            raise osv.except_osv(u'错误', u'此订单，存在两行产品相同的销售订单行！')
                        line_obj.write(cr, uid, line_row, {'delivery_quantity_qty': line_not_list[1]}, context=context)
                sale_obj.out_going_confirm(cr, uid, [sale_delivery.so_id.id], context=context)
                wizard_id = wizard_obj.create(cr, uid, {'sale_order_id': sale_delivery.so_id.id}, context=context)
                context.update({'default_sale_order_id': sale_delivery.so_id.id, 'on_move': True})
                return_result = wizard_obj.confirm_out_going(cr, uid, [wizard_id], context=context)
                picking_id = return_result.get('res_id')
                self.write_picking_address(cr, uid, sale_delivery.id, picking_id, context=context)
                if not picking_id:
                    raise osv.except_osv(u'错误', u'生成出库单失败！')
                sale_delivery.write({'is_exported': True, 'picking_id': picking_id})
                return return_result

    def view_picking_out_sale(self, cr, uid, ids, context=None):
        """点击按钮可以查，本条地址对应的系统中的出库单"""
        for sale_delivery in self.browse(cr, uid, ids, context=context):
            if sale_delivery.picking_id and sale_delivery.so_id:
                return self.pool.get('confirm.out.going.wizard').return_picking_action(cr, uid, sale_delivery.picking_id.id,
                                                                     False, sale_delivery.so_id, context=context)
            else:
                raise osv.except_osv(u'错误', u'没有可供查看的出库单！')

    def write_picking_address(self, cr, uid, delivery_id, picking_id, context=None):
        """导入快递单号的时候要生成出库单，这个时候要把生成的出库单的上的地址进行"""
        delivery_row = self.pool.get('sale.order.express.delivery').browse(cr, uid, delivery_id,
                                                                           context=context)
        vals = {
            'consignee': delivery_row.consignee,
            'province_id': self.search_name_id(cr, uid, 'res.country.state', delivery_row.province, 'name', context=context),
            'city_id': self.search_name_id(cr, uid, 'all.city', delivery_row.province, 'city_name', context=context),
            'county_id': self.search_name_id(cr, uid, 'all.county',  delivery_row.county, 'county_name', context=context),
            'street': delivery_row.street,
            'zip': '',
            'mobile_number': delivery_row.mobile_number,
            'phone_number': delivery_row.phone_number,
        }
        # self.pool.get('stock.picking').write(cr, uid, picking_id, vals, context=context)
        return self.pool.get('stock.picking').write(cr, uid, picking_id, vals, context=context)

    def search_name_id(self, cr, uid, model_name, name, field_name,context=None):
        model_ids = self.pool.get(model_name).search(cr, uid, [(field_name, '=', name)], context=context)
        return isinstance(model_ids, list) and model_ids and model_ids[0] or model_ids

#销售员导入发货地址列表
class sale_order_express_delivery_wizard(osv.osv):
    """#1049 增加一个销售订单快递发货表sale_order_express_delivery，如果销售订单的送货方式选择了“快递”，
    复制销售订单的发货联系人地址到sale_order_express_delivery，更多菜单里添加一个“excel导入快递发货地址”，
    检查“选择了快递送货方式才能导入快递发货地址”，导入前先清除本销售订单的所有sale_order_express_delivery
    记录 [置顶] [Issue开启]"""
    _name = 'sale.order.express.delivery.wizard'
    _inherit = ['import.wizard']
    _columns = {
        'so_id': fields.many2one('sale.order', u'销售订单'),
        'product_line': fields.text(u'订单的产品列表', readonly=True),
        'part_product_line': fields.text(u'每份发货产品列表', readonly=True),
        'delivery_qty': fields.text(u'发货地址数量', readonly=True),
    }
    _defaults = {
        'so_id': lambda s, c, u, ctx=None: s.pool.get('sale.order').browse(c, u, ctx.get('active_id'),
                                                                           context=ctx) or ctx.get('active_id'),
    }

    def need_column_date_header(self, cr, uid, context=None):
        vals = [('consignee', u"联系人"),('mobile_number', u"手机号码"), ('phone_number', u"电话号码"),
                ('province', u"省"), ('city', u"市"), ('county', u"县"), ('street', u"详细地址"), ('note', u"备注")
            , ('delivery_products', u"送货列表"), ('qty_note', u'数量(份数或者A2B1C3个数)')]
        return vals

    #单行建立
    def judge_and_write_vals(self, cr, uid, ids, data_dcit, context=None):
        model_obj = self.pool.get('sale.order.express.delivery')
        wizard_row = self.browse(cr, uid, ids, context=context)
        #订单产品列表
        product_line = eval(wizard_row.product_line)
        #每份产品列表(不包含服务类产品)
        part_product_line = eval(wizard_row.part_product_line)
        qty_note = data_dcit['qty_note']
        delivery_products = ''
        part_qty, order_id = 1, wizard_row.so_id.id
        order_line_json = {}
        if qty_note:
            try:
                part_qty = float(qty_note)
                for item in part_product_line:
                    if delivery_products:
                        delivery_products += '\n'
                    delivery_products += item['name'] + u' × ' + str(item['qty'] * part_qty)
                    order_line_json.setdefault(self.search_order_line_id(cr, uid, item['name'], order_id,
                                                                         item['qty'] * part_qty, context=context),
                                               []).append(item['qty'] * part_qty)
            except ValueError:
                #取得发货内容
                qty_list = re.compile(r'([a-z]{1}[0-9])', re.I|re.M).findall(qty_note)
                #取得发货内容
                for qty_item in qty_list:
                    product_line_index = ord(qty_item[0]) - 97
                    qty = int(qty_item[1:])
                    if delivery_products:
                        delivery_products += '\n'
                    delivery_products += product_line[product_line_index]['name'] + ' × ' + str(qty)
                    order_line_json.setdefault(
                        self.search_order_line_id(cr, uid, product_line[product_line_index]['name'], order_id,
                                                  qty, context=context), []).append(qty)
        else:
            for item in part_product_line:
                if delivery_products:
                    delivery_products += '\n'
                delivery_products += item['name'] + u' × ' + str(item['qty'] * part_qty)
                order_line_json.setdefault(
                    self.search_order_line_id(cr, uid, item['name'], order_id, item['qty'] * part_qty,
                                              context=context), []).append(item['qty'] * part_qty)
        if '.0' in str(data_dcit.get('mobile_number')):
            mobile_number = str(data_dcit.get('mobile_number')).replace('.0', '')
        else:
            mobile_number = str(data_dcit.get('mobile_number'))
        if '.0' in str(data_dcit.get('phone_number')):
            phone_number = str(data_dcit.get('phone_number')).replace('.0', '')
        else:
            phone_number = str(data_dcit.get('phone_number'))
        data_dcit.update({'so_id': wizard_row.so_id.id, 'delivery_products': delivery_products,
                          'order_line_json': order_line_json, 'mobile_number': mobile_number,
                          'phone_number': phone_number})
        data_dcit.update(self.check_model_data_repeat(cr, uid, data_dcit, model_obj, order_id, context=context))
        model_obj.create(cr, uid, data_dcit, context=context)
        return True

    def check_model_data_repeat(self, cr, uid, data_dcit, model_obj, order_id, context=None):
        """通过这个方法 验证 信息是否重复"""
        express_data = [str(val).replace(' ', '') for key, val in data_dcit.iteritems()
                        if
                        key in ['consignee', 'mobile_number', 'phone_number', 'province', 'city', 'county', 'street']]
        address_hash = model_obj.hashlib_express_val(''.join(express_data))
        model_id = model_obj.search(cr, uid, [('address_hash', '=', address_hash),
                                              ('so_id', '=', order_id)], context=context)
        if model_id:
            raise osv.except_osv(u'错误', u'%s 发货地址信息已经在系统中存在！' % data_dcit.get('consignee'))
        return {'address_hash': address_hash}

    def search_order_line_id(self, cr, uid, product_name, order_id, qty, context=None):
        """
        通过产品的名字，搜索到对应产品的订单行，顺便 验证下产品数量是否已经超过销售订单的产品的数量，如果多出来了，则要报错提醒
        """
        model_obj = self.pool.get('sale.order.express.delivery')
        line_obj = self.pool.get('sale.order.line')
        line_id = line_obj.search(cr, uid, [('product_id', '=', product_name),
                                            ('order_id', '=', order_id)], context=context)
        line_num_dict = {}
        for express_dict in model_obj.search_read(cr, uid, [('so_id', '=', order_id)],
                                                  ['order_line_json'], context=context):
            for key, val in eval(express_dict.get('order_line_json', '{}')).iteritems():
                line_num_dict.setdefault(key, []).extend(val)
        for line_dict in line_obj.search_read(cr, uid, [('id', 'in', line_num_dict.keys())], ['product_uom_qty'],
                                              context=context):
            if line_dict.get('product_uom_qty', 0) and line_num_dict.get(line_dict.get('id', False), []):
                if line_dict.get('product_uom_qty', 0) >= sum(line_num_dict.get(line_dict.get('id', False), [])) + qty:
                    return len(line_id) and isinstance(line_id, list) and line_id[0] or line_id
                else:
                    raise osv.except_osv(u'错误', u'%s 产品数量超过订单上的数量' % product_name)
            else:
                raise osv.except_osv(u'错误', u'%s 产品数量超过订单上的数量' % product_name)
        
        for line_dict in line_obj.search_read(cr, uid, [('id', 'in', line_id)], ['product_uom_qty'], context=context):
            if line_dict.get('product_uom_qty', 0) < qty:
                raise osv.except_osv(u'错误', u'%s 产品数量超过订单上的数量' % product_name)
        return len(line_id) and isinstance(line_id, list) and line_id[0] or line_id

    def return_vals_action(self, cr, uid, ids, this_id, context=None):
        model_obj = self.pool.get('sale.order.express.delivery')
        wizard_row = self.browse(cr, uid, ids, context=context)
        order_id = wizard_row[0].so_id.id
        order_lines = wizard_row[0].so_id.order_line
        #model_ids = model_obj.search(cr, uid, [('so_id', '=', order_id)], context=context)
        # exported_ids = model_obj.search(cr, uid, [('so_id', '=', order_id), ('is_exported', '=', True)],
        #                                  context=context)
        # if exported_ids:
        #     raise osv.except_osv(u'错误', u'已经被导出过送货信息，不能再次导入')
        #清除之前所有的发货记录(也就是每次导入会覆盖以前的)
        #model_obj.unlink(cr, uid, model_ids, context=context)
        #取得产品列表
        product_line = []
        for line in order_lines:
            product_qty = int(line.product_uom_qty)
            product_line.append({'name': line.product_id.display_name, 'qty': product_qty, 'type': line.product_id.type})

        #取得发货地址列表
        to_import = eval(wizard_row.to_import)
        #份数数量
        part_qty_sum = 0
        #把订单产品数量扣除掉指定发货数量(如qty_note为a1b2,表示扣除第一个产品1、第二个产品2)
        for line in to_import:
            qty_note = line.get('qty_note')
            qty = 1
            if qty_note:
                try:
                    qty = float(qty_note)
                except ValueError:
                    qty_note = qty_note.lower()
                    qty_list = re.compile(r'([a-z]{1}[0-9]+)', re.I|re.M).findall(qty_note)
                    for qty_item in qty_list:
                        product_line_index = ord(qty_item[0]) - 97
                        if product_line_index >= len(product_line):
                            raise osv.except_osv(u'错误', u'订单上产品个数和您输入的产品的个数不一致 ： %s' % qty_note)
                        product_line[product_line_index]['qty'] -= int(qty_item[1:])
                        if product_line[product_line_index]['qty'] < 0:
                            raise osv.except_osv(u'错误', u'产品 %s 数量不够给收货人 %s 分配: %s'
                                                 % (product_line[product_line_index]['name'],
                                                    line['consignee'], line['qty_note']))
            part_qty_sum += qty
        # #找出哪个产品的最小数量
        # min_qty = None
        # min_product_name = None
        # for line in product_line:
        #     if line['type'] <> 'service':
        #         if min_qty == None:
        #             min_qty = line['qty']
        #             min_product_name = line['name']
        #         else:
        #             if line['qty'] < min_qty:
        #                 min_qty = line['qty']
        #                 min_product_name = line['name']
        # if not min_qty:
        #     raise osv.except_osv(u'错误', u'没有需要发货的产品')
        # #检查扣除a1b2指定产品数量后的剩余数量跟"份数数量"part_qty_sum是否相符
        # #如果最小数量少于份数数量
        # if min_qty < part_qty_sum:
        #     raise osv.except_osv(u'错误', u'产品 %s 的数量 %s 不足以分配 %s 份发货数量' % (min_product_name, min_qty, part_qty_sum))

        #平均每份的产品数量
        # average_pre_part = min_qty / part_qty_sum
        #计算剩余数量(扣除指定数字的产品)最小单位可分配数量
        part_product_line = []
        for line in product_line:
            if line['type'] <> 'service':
                #当总份数大于0,才需要判断产品数量是否被最小数量整除
                # if part_qty_sum > 1 and line['qty'] % min_qty != 0:
                #     raise osv.except_osv(u'错误', u'产品 %s  数量 %s 不能被数量少的那个产品 %s 数量 %s 整除, 也就是不能凑成一份'
                #                          % (line['name'], line['qty'], min_product_name, min_qty))
                part_product_line.append({
                    'name': line['name'],
                    'qty': 1
                })
        #向导表写入so_id和发货地址数量
        val = {
            'so_id': context.get('active_id'),
            'delivery_qty': len(to_import),
            'product_line': product_line,
            'part_product_line': part_product_line
        }
        self.write(cr, uid, ids, val, context=context)

        return {
            'type': 'ir.actions.act_window',
            'res_model': 'sale.order.express.delivery.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'res_id': this_id,
            'views': [(False, 'form')],
            'target': 'new',
        }


class express_delivery_export_wizard(osv.osv):
    _name = 'express.delivery.export.wizard'
    _inherit = ['export.wizard']

    def model_fields_data_provide(self, cr, uid, context=None):
        model_obj = self.pool.get('sale.order.express.delivery')
        vals = [('id', u"内部序号"), ('so_id', u"销售订单"), ('consignee', u"联系人"), ('mobile_number', u"手机号码"),
                ('phone_number', u"电话号码"), ('province', u"省"), ('city', u"市"), ('county', u"县"), ('street', u"详细地址"),
                ('delivery_products', u"送货列表"), ('note', u"备注"), ('express_type_id', u"快递方式"),
                ('express_code', u"快递单号")]
        return model_obj, vals

    def return_vals_construction(self, cr, uid, ids, exported, this_id, out, to_export_ids, context=None):
        vals = {'data': out,
                'filename': u'销售订单快递发货地址%s.xls' % datetime.now().strftime("%Y%m%d"),
                'state': '2',
                'exported': exported}
        self.write(cr, uid, ids, vals, context=context)
        self.pool.get('sale.order.express.delivery').write(cr, uid, to_export_ids, {'is_export': True, 'export_date':datetime.now(),
                                                                'export_uid': uid},context=context)
        self.pool.get("sale.order.express.delivery").write(cr, uid, to_export_ids, {'is_exported': True},
                                                           context=context)
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'express.delivery.export.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'res_id': this_id,
            'views': [(False, 'form')],
            'target': 'new',
        }

#一单多发快递单号导入
class express_delivery_import_wizard(osv.osv):
    """049 增加一个销售订单快递发货表sale_order_express_delivery，如果销售订单的送货方式选择了“快递”，
    复制销售订单的发货联系人地址到sale_order_express_delivery，更多菜单里添加一个“excel导入快递发货地址”，
    检查“选择了快递送货方式才能导入快递发货地址”，导入前先清除本销售订单的所有sale_order_express_delivery记录
     [置顶] [Issue开启]"""
    _name = 'express.delivery.import.wizard'
    _inherit = ['import.wizard']

    def need_column_date_header(self, cr, uid, context=None):
        vals = [('id', u"内部序号"), ('so_id', u"销售订单"), ('consignee', u"联系人"), ('mobile_number', u"手机号码"),
                ('phone_number', u"电话号码"), ('province', u"省"), ('city', u"市"), ('county', u"县"), ('street', u"详细地址"),
                ('delivery_products', u"送货列表"), ('note', u"备注"), ('express_type_id', u"快递方式"),
                ('express_code', u"快递单号")]
        return vals

    def return_vals_action(self, cr, uid, ids, this_id, context=None):
        return {
            'type': 'ir.actions.act_window',
            'res_model': 'express.delivery.import.wizard',
            'view_mode': 'form',
            'view_type': 'form',
            'res_id': this_id,
            'views': [(False, 'form')],
            'target': 'new',
        }

    def judge_and_write_vals(self, cr, uid, ids, data_dcit, context=None):
        model_obj = self.pool.get('sale.order.express.delivery')
        express_type_id = self.pool.get('express.type').search(cr, uid,
                                                               [('name', '=', data_dcit.get('express_type_id'))],
                                                               context=context)
        if not express_type_id:
            raise osv.except_osv(u'错误', u'快递方式不存在！')
        data_dcit.update({'express_type_id': express_type_id[0]})
        split_str = '__export__.sale_order_express_delivery_'
        model_id = int(data_dcit.get('id').split(split_str)[1])
        model_obj.write(cr, uid, model_id,
                        {'express_type_id': data_dcit.get('express_type_id'),
                         'express_code': data_dcit.get('express_code')}, context=context)
        return model_id

    def button_ok(self, cr, uid, ids, context=None):
        delivery_obj = self.pool.get('sale.order.express.delivery')
        wizard = self.browse(cr, uid, ids, context=context)
        to_import = eval(wizard.to_import)
        if not to_import:
            raise osv.except_osv(u'错误', u'文件中没有需要导入的行')
        sale_order_express_dict = {}
        for data_dcit in to_import:
            delivery_id = self.judge_and_write_vals(cr, uid, ids, data_dcit, context=context)
            sale_order_express_dict.setdefault(data_dcit.get('so_id'), []).append(delivery_id)
        for order_id, delivery_list in sale_order_express_dict.iteritems():
            sale_order_json = {}
            for delivery in delivery_obj.browse(cr, uid, delivery_list, context=context):
                [sale_order_json.setdefault(line_id, []).extend(line_nums)
                 for line_id, line_nums in eval(delivery.order_line_json).iteritems()]
            self.line_write_and_create_picking(cr, uid, sale_order_json, order_id, delivery_list, context=context)
        return True

    def line_write_and_create_picking(self, cr, uid, line_data, order_name, delivery_id, context=None):
        sale_obj = self.pool.get('sale.order')
        order_id = sale_obj.search(cr, uid, [('name', '=', order_name)], context=context)
        order_id = order_id and isinstance(order_id, list) and order_id[0] or order_id
        delivery_obj = self.pool.get('sale.order.express.delivery')
        wizard_obj = self.pool.get("confirm.out.going.wizard")
        line_obj = self.pool.get('sale.order.line')
        for line_id, line_num in line_data.iteritems():
            line_obj.write(cr, uid, line_id, {'delivery_quantity_qty': sum(line_num)}, context=context)
        sale_obj.out_going_confirm(cr, uid, [order_id], context=context)
        wizard_id = wizard_obj.create(cr, uid, {'sale_order_id': order_id}, context=context)
        context.update({'default_sale_order_id': order_id})
        return_result = wizard_obj.confirm_out_going(cr, uid, [wizard_id], context=context)
        picking_id = return_result.get('res_id')
        #self.write_picking_address(cr, uid, delivery_id, picking_id, context=context)
        if not picking_id:
            raise osv.except_osv(u'错误', u'生成出库单失败！')
        delivery_obj.write(cr, uid, delivery_id, {'is_exported': True, 'picking_id': picking_id}, context=context)


class sale_order(osv.osv):
    _inherit = 'sale.order'

    _columns = {
        'express_delivery_ids': fields.one2many('sale.order.express.delivery','so_id',string=u'快递联系人地址',copy=False),
    }
